#! -*- Encoding: Latin-1 -*-

import sys
import os
import shutil
import zipfile
import copy
import traceback
import cStringIO
import pprint
import gettext
import win32api

def getarcname(filename):
    x = sys.path
    x.sort()
    x.reverse()
    for p in x:
        p = p.lower()
        if filename.lower().startswith(p):
            return filename[len(p)+1:]
    return filename

def extension(filename):
    k = filename.rfind(".")
    if k >= 0:
        return filename[k:].lower()
    return ""
    
class ModuleInfo(object):
    
    def __init__(self, targetdir, filename):
        self.targetdir = targetdir
        self.files_added = []    
        self.modules_ignored = []
        self.create_zipfile(filename)
        self.add_loaded_modules()
    
    def add(self, path, subdir = True):
        try:
            kOffset = path.rfind("\\")+1
            
            def embedd(directory):
                
                dfiles = {}
                
                if os.path.isdir(directory):
                    for filename in os.listdir(directory):
                        pathname = os.path.join(directory,filename)
                        if os.path.isdir(pathname):
                            embedd(pathname)
                        else:
                            dfiles[pathname] = pathname
                else:
                    dfiles[directory] = directory
                
                for filename in dfiles.keys():
                    if extension(filename) == ".py":
                        
                        # check if a .pyc is available; if so, prefer it.
                        
                        try:
                            existing = dfiles[filename + "c"]
                        except KeyError:
                            try:
                                existing = dfiles[filename + "o"]
                            except KeyError:
                                existing = None
                            
                        if existing is None:
                            existing = filename
                            
                        target = existing[kOffset:]
                        if not subdir:
                            k = target.find("\\")
                            if k:
                                target = target[k+1:]
                        self.add_file_to_archive(existing, target)
            embedd(path)
        except:
            traceback.print_exc()
    
    def flush(self):
        self.close_zipfile()
        
        output = cStringIO.StringIO()
        output.write("Added %d files:\r\n" % (len(self.files_added), ))
        self.files_added.sort()
        
        l0 = 0
        for item in self.files_added:
            arcname, longname = item
            if len(arcname) > l0:
                l0 = len(arcname)
                
        for item in self.files_added:
            output.write("- adding %r (%r)\r\n" % item)
        
        if self.modules_ignored:
            output.write("Warning, %d modules were ignored:\r\n" % (len(self.modules_ignored), ))
            for (name, module) in self.modules_ignored:
                output.write("- %r (%r)\r\n" % (name, module, ))
        print(output.getvalue())
            
    def add_loaded_modules(self):
        names = sys.modules.keys()
        names.sort()
        for modulename in names:
            self.add_loaded_module(sys.modules[modulename], modulename)
            
    def add_loaded_module(self, module, name):
        if module is None:
            return
            
        print "- found %r (%r)" % (name, module, )
        
        try:
            filename = module.__file__
        except:
            self.modules_ignored.append( (name, module, ) )
            return

        oldname = filename[:]
        filename = filename.lower()

        if filename.endswith(".pyc") or filename.endswith(".py"):
            self.add_file_to_archive(filename, getarcname(oldname))
            
        elif filename.endswith(".pyd"):
            bn = os.path.basename(filename)
            nname = os.path.join(self.targetdir, bn)
            self.files_added.append( (nname, filename) )
            shutil.copy( filename, nname )
                
        elif filename.endswith(".dll"):
            print ">> IGNORE %r" % filename

    def add_dll(self, filename):
        bn = os.path.basename(filename)
        nname = os.path.join(self.targetdir, bn)
        self.files_added.append( (nname, filename) )
        shutil.copy( filename, nname )

    def add_file_to_archive(self, filename, arcname):
        self.files_added.append( (arcname, filename) )
        
        try:
            existing = self.zfiles[arcname]
        except KeyError:
            existing = None
            
        if existing:
            if filename.lower() != existing.lower():
                print "---> WARNING, %s (%s) already exists as %s" % (arcname, filename, existing)
            return

        if arcname.endswith(".py"):
            try:
                existing = self.zfiles[arcname + "c"]
            except KeyError:
                try:
                    existing = self.zfiles[arcname + "o"]
                except KeyError:
                    existing = None
            
            if existing:
                print "--> WARNING %s already exists as %s" % (arcname, existing)
                return 

        try:
            self.z.write(filename, arcname)
            self.zfiles[arcname] = filename
        except Exception, e:
            print repr(e)
            traceback.print_exc( file = sys.stdout )

    def close_zipfile(self):
        self.z.close()

    def create_zipfile(self, filename):
        
        # make sure target directory exists
        try:
            os.makedirs(self.targetdir)
        except:
            pass
        
        zname = os.path.join(self.targetdir, "python-distribution.zip")
        print("Creating %r" % (zname, ))
        self.z = zipfile.ZipFile(zname, "w", zipfile.ZIP_DEFLATED)
        self.zfiles = {}
    
def generate_archive(targetdir, filename = "python.zip"):
    mi = ModuleInfo(targetdir, filename)
    mi.flush()

    